// i.r(t), i.d(t, { default: () => ZoomControls })
import { ZoomGetMaxCommand, ZoomInCommand, ZoomOutCommand, ZoomResetCommand, ZoomSetCommand } from "../command/zoom.command"
import CameraData from "../data/CameraData"
import SweepData from "../data/SweepData"
import ViewmodeData from "../data/ViewmodeData"
import EngineContext from "../EngineContext"
import hotKeyEnum, { KeyState } from "../enum/hotKey.enum"
import resolutionEnum from "../enum/resolution.enum"
import { PinchEvent } from "../event/GestureEvent"
import { KeyEvent } from "../event/KeyEvent"
import { ScrollEvent } from "../event/ScrollEvent"
import u from "../math/63560"
import f from "../math/7170"
import { ZoomMessage } from "../message/zoom.message"
import Sweep from "../object/Sweep"
import SymbolList from "../SymbolList"
import Matrix from "../three/Matrix"
import funcUtil from "../utils/func.util"
import Logger from "../utils/Logger"
import CameraModule from "./CameraModule"
import Module from "./Module"
import SweepPanoSolidModule from "./SweepPanoSolidModule"
import SweepPanoTilingModule from "./SweepPanoTilingModule"

const A = new Logger("Showcase Zoom Controls")
const y = 0.1
const b = 0.7
const S = 2
const E = 3
const T = 1.1
export default class ZoomControls extends Module {
  uhQuality: Record<string, boolean>
  config: any
  sweepTilingModule: SweepPanoSolidModule | SweepPanoTilingModule
  engine: EngineContext
  cameraModule: CameraModule
  cameraData: CameraData
  viewmodeData: ViewmodeData
  sweepData: SweepData
  zoomedSweep: Sweep
  constructor() {
    super(...arguments)
    this.name = "zoom-controls"
    this.uhQuality = {}
    this.config = { enabled: !0, tiles: !0 }
  }
  async init(e, t: EngineContext) {
    this.config.enabled = !!e.enabled
    this.config.tiles = !!e.tiles
    if (this.config.tiles)
      try {
        this.sweepTilingModule = await t.getModuleBySymbol<SweepPanoSolidModule>(SymbolList.SWEEP_PANO)
      } catch (e) {
        A.debug(`Tiling not enabled for zoom controls - ${e}`)
      }
    this.config.enabled && (await this.registerControls(t)), (this.engine = t)
    this.cameraModule = await t.getModule(CameraModule)
    this.cameraData = await t.market.waitForData(CameraData)
    this.viewmodeData = await t.market.waitForData(ViewmodeData)
    this.sweepData = await t.market.waitForData(SweepData)
    this.bindings.push(
      t.commandBinder.addBinding(ZoomInCommand, async e => this.zoomBy(e.step)),
      t.commandBinder.addBinding(ZoomOutCommand, async e => this.zoomBy(-e.step)),
      t.commandBinder.addBinding(ZoomResetCommand, async () => this.zoomTo(1)),
      t.commandBinder.addBinding(ZoomSetCommand, async e => this.zoomTo(e.value)),
      t.commandBinder.addBinding(ZoomGetMaxCommand, this.getMaxZoomAvailable.bind(this))
    )
  }
  async registerControls(e) {
    e.getModuleBySymbol(SymbolList.INPUT).then(e => {
      this.bindings.push(e.registerHandler(ScrollEvent, e => this.zoomByInput(this.scrollToZoomDelta(e)))),
        this.bindings.push(e.registerHandler(PinchEvent, e => this.zoomByInput(this.pinchToZoomDelta(e)))),
        this.bindings.push(e.registerHandler(KeyEvent, e => this.keyHandler(e)))
    })
  }
  zoomTo(e: number) {
    const t = this.cameraData.zoom()
    if (!this.validateViewmode()) return t
    const i = this.sweepData.currentSweepObject
    this.config.tiles && this.checkTilingZoomLevels(e, i)
    e = funcUtil.getMax(e, b, E)
    if (e !== t) {
      const t = f.ZY(this.cameraData.baseFovY / e)
      const i = u.oR.near
      const n = u.oR.far
      this.cameraModule.updateCameraProjection(new Matrix().makePerspectiveFov(t, this.cameraData.aspect(), i, n))
    }
    return this.engine.broadcast(new ZoomMessage(e)), e
  }
  checkTilingZoomLevels(e: number, t: Sweep) {
    e >= T && this.zoomedSweep !== t
      ? ((this.zoomedSweep = t),
        this.sweepTilingModule.enableZooming(!0, t).then(e => {
          e ? (this.uhQuality[t.id] = !0) : ((this.uhQuality[t.id] = !1), (this.zoomedSweep = void 0))
        }))
      : e < T && this.zoomedSweep && this.zoomedSweep === t && (this.sweepTilingModule.enableZooming(!1, this.zoomedSweep), (this.zoomedSweep = void 0))
  }
  getMaxZoom(e) {
    return this.uhQuality[e] ? E : S
  }
  zoomBy(e: number) {
    const t = this.cameraData.zoom()
    return this.validateViewmode() ? this.zoomTo(t + e) : t
  }
  validateViewmode() {
    return this.viewmodeData.isInside() && this.cameraData.canTransition()
  }
  scrollToZoomDelta(e) {
    return -Math.sign(e.delta.y) * y
  }
  pinchToZoomDelta(e) {
    return e.pinchDelta * (S - b)
  }
  zoomByInput(e) {
    const t = this.cameraData.zoom()
    if (!this.validateViewmode()) return t
    const i = this.sweepData.currentSweep
    const n = funcUtil.getMax(t + e, b, this.getMaxZoom(i))
    return this.zoomTo(n)
  }
  keyHandler(e) {
    if (e.state === KeyState.DOWN)
      switch (e.key) {
        case hotKeyEnum.PLUSEQUALS:
          this.zoomByInput(y)
          break
        case hotKeyEnum.DASHUNDERSCORE:
          this.zoomByInput(-y)
          break
        case hotKeyEnum.OPENBRACKET:
          this.zoomTo(1)
      }
  }
  async getMaxZoomAvailable() {
    if (!this.sweepData.currentSweepObject) return S
    const e = this.sweepData.currentSweepObject
    return (await this.sweepTilingModule.availableResolution(e, resolutionEnum.ULTRAHIGH)) >= resolutionEnum.ULTRAHIGH ? E : S
  }
}
